﻿using System;
using System.Diagnostics;
using System.IO;
using System.Security.Cryptography;
using System.Windows.Forms;
using EncryptionLib;
using EncryptionLib.Encryption;
using EncryptionLib.Signature;
using EncryptionLib.Users;

namespace EncryptionTest
{
    public partial class frmMain : Form
    {
        // use e temporary file to save.
        IUserManager m_userManager = new UserManagerXML();

        public frmMain()
        {
            InitializeComponent();

            cmbEncryptAlgorithm.Items.Add(SymmetricAlgorithms.DES);
            cmbEncryptAlgorithm.Items.Add(SymmetricAlgorithms.RC2);
            cmbEncryptAlgorithm.Items.Add(SymmetricAlgorithms.Rijndael);
            cmbEncryptAlgorithm.Items.Add(SymmetricAlgorithms.TripleDES);
            cmbEncryptAlgorithm.SelectedIndex = 0;

            cmbEncryptCipherMode.Items.Add(CipherMode.CBC);
            cmbEncryptCipherMode.Items.Add(CipherMode.CFB);
            cmbEncryptCipherMode.Items.Add(CipherMode.CTS);
            cmbEncryptCipherMode.Items.Add(CipherMode.ECB);
            cmbEncryptCipherMode.Items.Add(CipherMode.OFB);
            cmbEncryptCipherMode.SelectedIndex = 0;

            cmbEncryptPaddingMode.Items.Add(PaddingMode.ANSIX923);
            cmbEncryptPaddingMode.Items.Add(PaddingMode.ISO10126);
            cmbEncryptPaddingMode.Items.Add(PaddingMode.None);
            cmbEncryptPaddingMode.Items.Add(PaddingMode.PKCS7);
            cmbEncryptPaddingMode.Items.Add(PaddingMode.Zeros);
            cmbEncryptPaddingMode.SelectedIndex = 0;
        }

        #region private utilities

        private void BrowseXMLFile(TextBox txt, bool bOpen)
        {
            FileDialog dlg;
            if (bOpen)
            {
                dlg = new OpenFileDialog();
                dlg.AutoUpgradeEnabled = dlg.CheckFileExists = dlg.CheckPathExists = true;
                dlg.Title = "Open a xml file.";
            }
            else
            {
                dlg = new SaveFileDialog();
                dlg.Title = "Save to a xml file.";
            }
            dlg.Filter = "XML files (*.xml)|*.xml||";

            if (dlg.ShowDialog(this) == DialogResult.OK)
                txt.Text = dlg.FileName;
        }

        private void UpdateEncryptZip()
        {
            if(lstEncryptInputFiles.Items.Count > 1)
            {
                chkEncryptZip.Enabled = false;
                chkEncryptZip.Checked = true;
            }
            else if(lstEncryptInputFiles.Items.Count == 1)
            {
                chkEncryptZip.Enabled = true;
            }

        }

        private UserData Login()
        {
            frmLogin frm = new frmLogin();
            UserData userRet = null;
            if(frm.ShowDialog(this) == DialogResult.OK)
            {
                userRet = m_userManager.LoginByEmail(frm.Email, frm.Passphrase);
                MessageBox.Show(this, userRet == null ? "Failed" : "Success", "Encryption");
            }
            return userRet;
        }

        private void UpdateUserList()
        {
            cmbEncryptReceiver.Items.Clear();
            for(int i = m_userManager.GetCount() - 1; i >= 0; --i)
            {
                cmbEncryptReceiver.Items.Add(m_userManager.GetUser(i));
            }
            if(cmbEncryptReceiver.Items.Count > 0)
            {
                cmbEncryptReceiver.SelectedIndex = 0;
            }
        }

        #endregion

        #region users

        private void llblUserLoad_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            BrowseXMLFile(txtUserLoad, true);
        }

        private void llblUserSave_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            BrowseXMLFile(txtUserSave, false);
        }

        private void llblUserExport_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            BrowseXMLFile(txtUserExport, false);
        }

        private void llblUserImport_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            BrowseXMLFile(txtUserImport, true);
        }

        private void btnUserLoad_Click(object sender, EventArgs e)
        {
            string sFile = txtUserLoad.Text;
            if (!string.IsNullOrEmpty(sFile))
            {
                // save current data
                m_userManager.SaveData();

                // load new database
                m_userManager = new UserManagerXML(sFile);
                UpdateUserList();
            }
        }

        private void btnUserSave_Click(object sender, EventArgs e)
        {
            string sFile = txtUserSave.Text;
            if (!string.IsNullOrEmpty(sFile))
            {
                // save current data
                ((UserManagerXML)m_userManager).SaveData(sFile);
                m_userManager.SaveData();
            }
        }

        private void btnUserExport_Click(object sender, EventArgs e)
        {
            string sFile = txtUserExport.Text;
            if (!string.IsNullOrEmpty(sFile) && m_userManager.GetCount() > 0)
            {
                UserData userData = m_userManager.GetUser(0);
                Debug.Assert(UserManagerXML.ExportUserData(userData, sFile));
            }
        }

        private void btnUserImport_Click(object sender, EventArgs e)
        {
            string sFile = txtUserExport.Text;
            if (!string.IsNullOrEmpty(sFile))
            {
                UserData user = UserManagerXML.ImportUserData(sFile);
                Debug.Assert(user != null);
            }
        }

        private void btnUserAdd_Click(object sender, EventArgs e)
        {
            UserData user = new UserData("abc@xyz.com", "ABC",
                new DateTime(1988, 10, 1), "0911111111", "Hell",
                "12345678",                     // user's passphrase
                576);                           // encrpytion key len

            if (m_userManager.GetUserByEmail(user.Email) == null)
            {
                Debug.Assert(m_userManager.Register(user));
                MessageBox.Show(this, "Successful!", "Encryption");
            }
            else
            {
                MessageBox.Show(this, "This user is existed.", "Encryption");
            }
        }

        private void btnClear_Click(object sender, EventArgs e)
        {
            m_userManager.Clear();
            Debug.Assert(m_userManager.GetCount() == 0);
        }

        private void btnLogin_Click(object sender, EventArgs e)
        {
            Login();
        }

        #endregion

        #region Encrpytion

        private void btnEncryptAdd_Click(object sender, EventArgs e)
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Multiselect = dlg.AutoUpgradeEnabled = dlg.CheckFileExists = dlg.CheckPathExists = true;
            dlg.Title = "Add more files...";
            dlg.Filter = "All files (*.*)|*.*||";
            if (dlg.ShowDialog(this) == DialogResult.OK)
            {
                foreach (string s in dlg.FileNames)
                {
                    if (!lstEncryptInputFiles.Items.Contains(s))
                    {
                        lstEncryptInputFiles.Items.Add(s);
                    }
                }
                UpdateEncryptZip();
            }
        }

        private void btnAddFolder_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog dlg = new FolderBrowserDialog();
            dlg.Description = "Add a folder to encrypted file...";
            if(dlg.ShowDialog(this) == DialogResult.OK)
            {
                if (!lstEncryptInputFiles.Items.Contains(dlg.SelectedPath))
                    lstEncryptInputFiles.Items.Add(dlg.SelectedPath);
            }
        }

        private void btnEncryptRemove_Click(object sender, EventArgs e)
        {
            if (lstEncryptInputFiles.SelectedIndex >= 0)
            {
                lstEncryptInputFiles.Items.RemoveAt(lstEncryptInputFiles.SelectedIndex);
                lstEncryptInputFiles.Focus();
                UpdateEncryptZip();
            }
        }

        private void btnEncryptOutput_Click(object sender, EventArgs e)
        {
            SaveFileDialog dlg = new SaveFileDialog();
            dlg.RestoreDirectory = dlg.OverwritePrompt = dlg.AutoUpgradeEnabled = dlg.AddExtension = true;
            dlg.Title = "Save the encrypted file";
            dlg.Filter = "VAF files (*.vaf)|*.vaf||";
            dlg.DefaultExt = "vaf";
            if(dlg.ShowDialog(this) == DialogResult.OK)
            {
                txtEncryptOutputFile.Text = dlg.FileName;
            }
        }

        private void btnEncryptAction_Click(object sender, EventArgs e)
        {
            try
            {
                Encryptor encryptor = new Encryptor();
                encryptor.Algorithm = (SymmetricAlgorithms)cmbEncryptAlgorithm.SelectedItem;
                encryptor.CipherMode = (CipherMode)cmbEncryptCipherMode.SelectedItem;
                encryptor.OutputFile = txtEncryptOutputFile.Text;
                encryptor.PaddingMode = (PaddingMode)cmbEncryptPaddingMode.SelectedItem;
                encryptor.Zipped = chkEncryptZip.Checked;

                // to make sure we got FILES only.
                foreach(object obj in lstEncryptInputFiles.Items)
                {
                    string sPath = (string)obj;
                    if(Directory.Exists(sPath))
                    {
                        foreach(string sFile in Directory.GetFiles(sPath, "*.*", SearchOption.AllDirectories))
                        {
                            if(!encryptor.Files.Contains(sFile)
                                && File.Exists(sFile))
                                encryptor.Files.Add(sFile);
                        }
                    }
                    if (!encryptor.Files.Contains(sPath) && File.Exists(sPath))
                        encryptor.Files.Add(sPath);
                }
                encryptor.Reciever = (UserData)cmbEncryptReceiver.SelectedItem;

                // this is the old way...
                //encryptor.Encrypt();
                //MessageBox.Show(this, "Successfully!", "Congrats", MessageBoxButtons.OK, MessageBoxIcon.Information);

                // this is the new way...
                encryptor.EncryptAsyncProgess += new EncryptionProgressHandler(encryptor_EncryptAsyncProgess);
                encryptor.EncryptAsync(this);

                btnEncryptDecrypt.Enabled = true;

            }
            catch (System.Exception ex)
            {
                MessageBox.Show(this, string.Format("Error:\r\n{0}", ex.Message), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        void encryptor_EncryptAsyncProgess(object sender, EncryptionProgressArgs args)
        {
            if (args.Progress == -1)
            {
                MessageBox.Show(this,
                    string.Format("An unexpected error has occurred when encrypting.\r\n\r\nError: {0}", args.ProgressExeption.Message),
                    "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            else
            {
                prbarEncrypt.Value = args.Progress;
                if (args.Progress == 100)
                {
                    MessageBox.Show(this, "Done!", "Success");
                }
                Debug.WriteLine(string.Format("Encrypt: {0}", args.Progress));
            }
        }

        private void btnEncryptDecrypt_Click(object sender, EventArgs e)
        {
            try
            {
                frmLogin frm = new frmLogin();
                if (frm.ShowDialog(this) != DialogResult.OK)
                    return;

                UserData receiver = m_userManager.LoginByEmail(frm.Email, frm.Passphrase);
                if(receiver == null)
                {
                    MessageBox.Show(this, "This user is not existed.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }

                Decryptor decryptor = new Decryptor();
                decryptor.EncryptedFile = txtEncryptOutputFile.Text;
                decryptor.OutputPath = 
                    Path.Combine(Path.GetDirectoryName(decryptor.EncryptedFile), "unzipped");
                decryptor.Receiver = receiver;

                // old way
                //decryptor.Decrypt(frm.Passphrase);
                //MessageBox.Show(this, "Successfully!", "Congrats", MessageBoxButtons.OK, MessageBoxIcon.Information);

                // new way
                decryptor.DecryptAsyncProgress += new EncryptionProgressHandler(decryptor_DecryptAsyncProgress);
                decryptor.DecryptAsync(this, frm.Passphrase);

            }
            catch (System.Exception ex)
            {
                MessageBox.Show(this, string.Format("Error:\r\n{0}", ex.Message), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        void decryptor_DecryptAsyncProgress(object sender, EncryptionProgressArgs args)
        {
            if (args.Progress == -1)
            {
                MessageBox.Show(this, "Error when decrypting!", "Error");
            }
            else 
            {
                prbarEncrypt.Value = args.Progress;
                if (args.Progress == 100)
                {
                    MessageBox.Show(this, "Done!", "Success");
                }
                Debug.WriteLine(string.Format("Decrypt: {0}", args.Progress));
            }
        }

        #endregion

        #region signature

        private void btnSignInputFile_Click(object sender, EventArgs e)
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.AutoUpgradeEnabled = dlg.CheckFileExists = dlg.CheckPathExists = true;
            dlg.Filter = "All files (*.*)|*.*||";
            dlg.Title = "Open a file to sign.";
            if(dlg.ShowDialog(this) == DialogResult.OK)
            {
                txtSignInputFile.Text = dlg.FileName;
            }
        }

        private void btnSignSignFile_Click(object sender, EventArgs e)
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.AutoUpgradeEnabled = dlg.CheckFileExists = dlg.CheckPathExists = true;
            dlg.Filter = "Signature file (*.sig)|*.sig||";
            dlg.Title = "Open a signature file.";
            if (dlg.ShowDialog(this) == DialogResult.OK)
            {
                txtSignSignFile.Text = dlg.FileName;
            }
        }

        private void txtSignInputFile_TextChanged(object sender, EventArgs e)
        {
            if (!string.IsNullOrEmpty(txtSignInputFile.Text))
                txtSignSignFile.Text = txtSignInputFile.Text + ".sig";
        }

        private void btnSignSign_Click(object sender, EventArgs e)
        {
            frmLogin frm = new frmLogin();
            if(frm.ShowDialog(this) == DialogResult.OK)
            {
                UserData userData = m_userManager.LoginByEmail(frm.Email, frm.Passphrase);
                if(userData != null)
                {
                    try
                    {
                        Signer.Sign(userData, frm.Passphrase, txtSignInputFile.Text,
                            txtSignSignFile.Text);
                    }
                    catch(Exception ex)
                    {
                        MessageBox.Show(this, "Error:\r\n" + ex.Message, "Error",
                            MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
                else
                {
                    MessageBox.Show(this, "Login failed!", "Error",
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        private void btnSignVerify_Click(object sender, EventArgs e)
        {
            string sDateFile = txtSignInputFile.Text;
            string sSignFile = txtSignSignFile.Text;

            try
            {
                for (int i = m_userManager.GetCount() - 1; i >= 0; --i)
                {
                    UserData user = m_userManager.GetUser(i);
                    if (Signer.Verify(user, sDateFile, sSignFile))
                    {
                        MessageBox.Show(this,
                            "Verify SUCESSFUL!.\r\n This file was signed by " + user.Email,
                            "Congrats", MessageBoxButtons.OK, MessageBoxIcon.Information);
                        return;
                    }
                }
                MessageBox.Show(this, "Cannot verify thw signature :(",
                    "Failed", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(this, "Error:\r\n" + ex.Message, "Error",
                            MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            
        }

        #endregion

        private void prbarEncrypt_Click(object sender, EventArgs e)
        {

        }

        private void frmMain_Load(object sender, EventArgs e)
        {

        }

    }
}
